Understanding the useState Hook in React JS
Topic: Understanding the useState Hook
Technology: React JS
React JS Training: JustAcademy React JS Training Course
Course Demo: Register for React JS Course Demo
1. Introduction to the useState Hook
The useState Hook is a built-in React function that allows functional components to store, manage, and update information over time. It helps create interactive user interfaces that respond to user actions such as clicking buttons, entering text, selecting options, and submitting forms.
When a state setter is called, React schedules an update and renders the component again when necessary so the interface can display the updated state.
For example, a counter application can use useState to remember the current count and update it whenever a user clicks the Increase button.
Example
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<h2>Count: {count}</h2>
<button onClick={() => setCount(count + 1)}>
Increase
</button>
</div>
);
}
export default Counter;
Explanation: The count variable stores the current count, setCount requests an update, and useState initializes the count to 0.
2. What Is a React Hook?
A Hook is a special React function that allows functional components to use React features such as state, context, and effects. Hook names begin with the word use, such as useState, useEffect, and useContext.
The useState Hook specifically provides state management for functional components.
Examples of React Hooks
| Hook |
Purpose |
useState |
Stores and updates component state. |
useEffect |
Synchronizes a component with external systems. |
useContext |
Reads values from React Context. |
useRef |
Stores a value or references a DOM element without triggering a render when the ref changes. |
useReducer |
Manages state through a reducer function. |
3. Why Do We Need the useState Hook?
Regular JavaScript variables are not sufficient when a component needs to remember a value between renders and display changes automatically. Changing a local variable does not tell React to render the component again.
The useState Hook solves this problem by providing:
- A state value that React remembers between renders.
- A setter function to request a state update.
- A way to keep the displayed UI synchronized with the latest state.
Example Without useState
function Counter() {
let count = 0;
function increase() {
count = count + 1;
}
return (
<div>
<p>Count: {count}</p>
<button onClick={increase}>Increase</button>
</div>
);
}
This example does not work as intended. Changing count does not trigger a render, and a later render initializes the local variable again.
Example With useState
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increase
</button>
</div>
);
}
Here, React remembers count between renders and updates the displayed value when setCount is called.
4. Syntax of the useState Hook
General Syntax
const [state, setState] = useState(initialState);
Explanation of each part:
state: The current state value available during the current render.
setState: The function used to request a state update.
useState(): The React Hook that declares a state variable.
initialState: The value used to initialize state during the component's first render.
[]: JavaScript array destructuring is used to assign the two returned values to separate variables.
Example
import { useState } from "react";
function App() {
const [name, setName] = useState("Rahul");
return <h2>Name: {name}</h2>;
}
export default App;
The name state starts with Rahul. The setName function can request a different value when needed.
5. Understanding the Two Values Returned by useState
The useState Hook returns an array containing two values.
5.1 Current State Value
The first value is the current state. It can be displayed in JSX or used in calculations.
const [count, setCount] = useState(0);
<p>Current Count: {count}</p>
5.2 State Setter Function
The second value is a function used to request the next state value.
setCount(count + 1);
When the setter is called, React schedules a state update and renders the component again when necessary.
6. Initializing State with Different Data Types
The useState Hook can store different JavaScript data types depending on the information the component needs to remember.
6.1 Number State
const [age, setAge] = useState(25);
Useful for counters, quantities, scores, and ratings.
6.2 String State
const [name, setName] = useState("Amit");
Useful for names, messages, search queries, and text inputs.
6.3 Boolean State
const [isVisible, setIsVisible] = useState(false);
Useful for showing or hiding content, opening menus, and tracking enabled or disabled options.
6.4 Array State
const [skills, setSkills] = useState(["HTML", "CSS", "React"]);
Useful for lists of tasks, products, students, or selected items.
6.5 Object State
const [user, setUser] = useState({
name: "Aarav",
city: "Mumbai"
});
Useful for related information such as profile details and form data.
7. Updating State Using the Setter Function
To update state, call the setter function returned by useState. Do not assign a new value directly to the state variable.
Example
import { useState } from "react";
function NameChanger() {
const [name, setName] = useState("Amit");
return (
<div>
<h2>{name}</h2>
<button onClick={() => setName("Priya")}>
Change Name
</button>
</div>
);
}
export default NameChanger;
Initially, the heading displays Amit. Clicking the button requests an update to Priya.
Important Point
A setter does not change the state variable in the currently executing render. State behaves like a snapshot for that render. The updated value becomes available when React renders the component again.
8. Updating State Based on the Previous State
When a new state value depends on the previous value, use the functional updater form. This is particularly useful when multiple state updates are queued.
Syntax
setCount(previousCount => previousCount + 1);
Example: Increase Count by Three
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
function increaseByThree() {
setCount(previousCount => previousCount + 1);
setCount(previousCount => previousCount + 1);
setCount(previousCount => previousCount + 1);
}
return (
<div>
<h2>Count: {count}</h2>
<button onClick={increaseByThree}>Increase by 3</button>
</div>
);
}
export default Counter;
Each updater receives the pending previous value and calculates the next value. Clicking the button increases the count by three.
9. Using Multiple useState Hooks
A functional component can use multiple useState Hooks to manage separate pieces of information. This is useful when each value has its own purpose or update behavior.
Example
import { useState } from "react";
function Profile() {
const [name, setName] = useState("Neha");
const [age, setAge] = useState(22);
const [city, setCity] = useState("Mumbai");
return (
<div>
<p>Name: {name}</p>
<p>Age: {age}</p>
<p>City: {city}</p>
<button onClick={() => setName("Riya")}>Change Name</button>
<button onClick={() => setAge(age + 1)}>Increase Age</button>
<button onClick={() => setCity("Pune")}>Change City</button>
</div>
);
}
export default Profile;
Each state variable stores a separate value, and its corresponding setter updates that value.
10. Lazy Initialization with useState
If calculating the initial state is expensive, you can pass an initializer function to useState. React calls the initializer to calculate the initial value during initialization rather than treating its result as an ordinary value on every render.
Example
import { useState } from "react";
function createInitialCount() {
console.log("Calculating initial count");
return 10;
}
function Counter() {
const [count, setCount] = useState(createInitialCount);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increase</button>
</div>
);
}
export default Counter;
Notice that the function is passed as useState(createInitialCount), not called as useState(createInitialCount()). In development Strict Mode, React may call initializer functions more than once to help identify unintended side effects, so initializers should be pure.
11. Updating Object State Correctly
Objects stored in state should be treated as read-only. Create a new object with the changed property instead of modifying the existing object.
Example
import { useState } from "react";
function UserProfile() {
const [user, setUser] = useState({
name: "Aarav",
city: "Mumbai"
});
function changeCity() {
setUser(previousUser => ({
...previousUser,
city: "Pune"
}));
}
return (
<div>
<p>Name: {user.name}</p>
<p>City: {user.city}</p>
<button onClick={changeCity}>Change City</button>
</div>
);
}
export default UserProfile;
The spread syntax copies the existing properties, while city is updated in the new object.
12. Updating Array State Correctly
When updating an array in state, create a new array instead of modifying the existing array directly.
Example: Adding an Item
import { useState } from "react";
function TodoList() {
const [todos, setTodos] = useState(["Learn HTML", "Learn CSS"]);
function addTodo() {
setTodos(previousTodos => [...previousTodos, "Learn React"]);
}
return (
<div>
<ul>
{todos.map(todo => (
<li key={todo}>{todo}</li>
))}
</ul>
<button onClick={addTodo}>Add Task</button>
</div>
);
}
export default TodoList;
The spread syntax copies the previous items into a new array and adds Learn React to the end.
13. Using useState with Event Handling
State is frequently updated in response to events such as button clicks, form submissions, text input, and checkbox changes.
Example: Toggle Message Visibility
import { useState } from "react";
function ToggleMessage() {
const [isVisible, setIsVisible] = useState(false);
return (
<div>
<button onClick={() => setIsVisible(previous => !previous)}>
{isVisible ? "Hide Message" : "Show Message"}
</button>
{isVisible && <p>Welcome to React JS!</p>}
</div>
);
}
export default ToggleMessage;
The button toggles isVisible between true and false. The message is rendered only when isVisible is true.
14. Using useState with Form Inputs
The useState Hook can manage form data. In a controlled input, the value attribute reads from state, and the onChange handler updates state whenever the user types.
Example
import { useState } from "react";
function NameForm() {
const [name, setName] = useState("");
return (
<div>
<label htmlFor="name">Enter your name: </label>
<input
id="name"
value={name}
onChange={event => setName(event.target.value)}
/>
<p>Your name is: {name}</p>
</div>
);
}
export default NameForm;
Every change to the input updates name state, and the paragraph displays the current value.
15. Rules of Using the useState Hook
- Call useState at the top level of a functional component or custom Hook.
- Do not call useState inside conditions, loops, or nested functions.
- Call state setters to request updates instead of assigning to state variables.
- Treat arrays and objects in state as read-only.
- Use functional updater syntax when the next value depends on the previous value.
- Keep state variables clear and meaningful.
- Keep initializer functions pure and free of side effects.
16. Common Mistakes When Using useState
| Mistake |
Why It Is a Problem |
Correct Approach |
| Changing a regular variable |
It does not trigger a React render. |
Use useState for information the UI must remember. |
| Assigning directly to state |
It does not correctly request a state update. |
Use the setter function. |
| Mutating an object or array |
It can cause inconsistent UI behavior. |
Create a new object or array. |
| Expecting immediate state changes |
The current render keeps its existing state snapshot. |
Use the updated value on a subsequent render. |
| Calling useState conditionally |
It violates the Rules of Hooks. |
Call Hooks unconditionally at the top level. |
| Passing a function when you intend to store a function |
A function passed to useState is treated as an initializer. |
To store a function itself, use a lazy initializer that returns it, such as useState(() => myFunction). |
17. Difference Between useState and Regular Variables
| Feature |
Regular Variable |
useState |
| Remembers values between renders |
No, local variables are recreated when the component function runs. |
Yes, React preserves the state value. |
| Triggers a render when changed |
No. |
Calling the setter requests an update. |
| Best use |
Temporary calculations within a render. |
Values that affect the UI and must persist. |
| Example |
let count = 0; |
const [count, setCount] = useState(0); |
18. Difference Between Props and useState
| Feature |
Props |
useState |
| Purpose |
Pass information into a component. |
Manage information a component needs to remember. |
| Source |
Usually supplied by a parent. |
Declared inside the component or state-owning component. |
| Updating |
The parent supplies new prop values. |
The setter requests a state update. |
| Example |
|
const [name, setName] = useState("Riya"); |
19. Practical Project: Counter Application
Objective: Build a counter using useState with Increase, Decrease, and Reset buttons.
App.jsx
import { useState } from "react";
function App() {
const [count, setCount] = useState(0);
return (
<div>
<h1>Counter Application</h1>
<h2>Count: {count}</h2>
<button onClick={() => setCount(previous => previous + 1)}>Increase</button>
<button onClick={() => setCount(previous => previous - 1)}>Decrease</button>
<button onClick={() => setCount(0)}>Reset</button>
</div>
);
}
export default App;
Project Outcome: The count is stored in state. The buttons update it, and React displays the latest value after each update.
20. Interview Questions and Answers
Q1. What is the useState Hook?
useState is a built-in React Hook that lets functional components declare and update state variables.
Q2. What does useState return?
It returns an array containing the current state value and a setter function.
Q3. What is the purpose of the initial state?
It specifies the state value used during the component's initial render.
Q4. Can a component use multiple useState Hooks?
Yes. A component can use multiple state variables to manage separate pieces of information.
Q5. Why does React re-render after a state update?
React needs to render the component with the updated state so the UI can reflect the latest information.
Q6. Why should state not be modified directly?
State should be treated as read-only. Use the setter and create new objects or arrays when updating structured state.
Q7. When should functional updater syntax be used?
Use it when the next state depends on the previous state, such as incrementing a counter.
Q8. Can useState store objects and arrays?
Yes. It can store any JavaScript value, including objects and arrays.
Q9. What are the Rules of Hooks?
Hooks must be called at the top level of React components or custom Hooks, not inside conditions, loops, or nested functions.
Q10. What is lazy initialization?
Lazy initialization passes a function to useState so React can call it to calculate the initial state.
21. Practice Exercises
- Create a counter that increases when a button is clicked.
- Create a button that changes a message using state.
- Build a show/hide message feature using boolean state.
- Create a form that stores and displays a user's name.
- Build a task list that adds new tasks using array state.
- Create a profile that updates a city stored in object state.
- Build a Like button that toggles between Like and Liked.
- Create a counter with Increase, Decrease, and Reset buttons.
- Use a functional updater to increase a counter by three in one click.
- Create a component that uses multiple state variables for name and age.
22. Best Practices for Using useState
- Use descriptive state variable and setter names.
- Keep state as simple as possible.
- Use state for information that must persist between renders and affect the UI.
- Calculate values from existing props or state when storing them separately is unnecessary.
- Use functional updater syntax when the next state depends on the previous state.
- Create new objects and arrays instead of mutating existing state.
- Use lazy initialization for expensive initial calculations.
- Keep state in the component that needs to own and coordinate it.
23. Quick Revision Checklist
- Understand what a React Hook is.
- Know how to import useState.
- Understand the syntax and returned values of useState.
- Practice storing numbers, strings, booleans, arrays, and objects.
- Know how to update state with a setter function.
- Understand functional updater syntax.
- Know how to update arrays and objects without mutation.
- Understand the Rules of Hooks.
- Practice creating interactive components.
24. Useful Learning Resources
25. Conclusion
The useState Hook is an essential React feature for building interactive applications. It allows functional components to remember information between renders and update the UI when state changes. Understanding state initialization, setter functions, functional updates, and safe handling of arrays and objects helps developers write reliable and maintainable React code.
Explore React JS Training: JustAcademy React JS Training Course
Register for a Course Demo: Register for React JS Course Demo